﻿using NHibernate;
using NHibernate.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Mengsk.ProxyDelivery.Dao.HibernateImpl
{
    public abstract class HibernateDao<E> : IDao<E>
    {
        protected ISession OpenSession()
        {
            return NHibernateHelper.OpenSession();
        }

        public E GetById(object id)
        {
            ISession session = OpenSession();
            try
            {
                return (E)this.OpenSession().Get(this.GetType(), id);
            }
            finally
            {
                session.Close();
            }
        }

        public E GetByField(string field, object value)
        {
            ISession session = this.OpenSession();
            try
            {
                return (E)(this.OpenSession().CreateQuery("from " + this.GetType().Name + " where " + field + "=?").SetParameter(0, value).UniqueResult());
            }
            finally
            {
                session.Close();
            }
        }

        public IList<E> GetAllByField(string field, object value)
        {
            ISession session = this.OpenSession();
            try
            {
                return this.OpenSession().CreateQuery("from " + this.GetType().Name + " where " + field + "=?").SetParameter(0, value).List<E>();
            }
            finally
            {
                session.Close();
            }
        }

        public E GetByFieldLike(string field, string value)
        {
            ISession session = this.OpenSession();
            try
            {
                return this.OpenSession().CreateQuery("from " + this.GetType().Name + " where " + field + "like '%?%'").SetParameter(0, value).UniqueResult<E>();
            }
            finally
            {
                session.Close();
            }
        }

        public IList<E> GetAllByFieldLike(string field, string value)
        {
            ISession session = this.OpenSession();
            try
            {
                return this.OpenSession().CreateQuery("from " + this.GetType().Name + " where " + field + "like '%?%'").SetParameter(0, value).List<E>();
            }
            finally
            {
                session.Close();
            }
        }

        public int GetCount(Dictionary<string, object> param)
        {
            string query = param.Keys.Aggregate((sum, current) => sum + " and " + current + "=?");
            return this.GetCount(query, param.Values.ToArray());
        }

        public int GetCount(string query, params object[] objects)
        {
            ISession session = this.OpenSession();
            try
            {
                IQuery hQuery = session.CreateQuery(query);

                for (int i = 0; objects != null && i < objects.Length; i++)
                {
                    hQuery.SetParameter(i, objects[i]);
                }
                return int.Parse(hQuery.UniqueResult().ToString());
            }
            finally
            {
                session.Close();
            }
        }

        public IList<E> Get(Dictionary<string, object> param, int pageIndex, int pageSize)
        {
            string query = param.Keys.Aggregate((sum, current) => sum + " and " + current + "=?");
            return this.Get(query, pageIndex, pageSize);
        }

        public IList<E> Get(string query, int pageIndex, int pageSize, params object[] objects)
        {
            ISession session = this.OpenSession();
            try
            {
                IQuery hQuery = session.CreateQuery(query);

                for (int i = 0; objects != null && i < objects.Length; i++)
                {
                    hQuery.SetParameter(i, objects[i]);
                }
                if (pageSize > 0)
                {
                    hQuery.SetMaxResults(pageSize);
                    hQuery.SetFirstResult(pageSize * pageIndex);
                }
                return hQuery.List<E>();
            }
            finally
            {
                session.Close();
            }
        }

        public void Save(params object[] objects)
        {
            ISession session = this.OpenSession();
            ITransaction tx = null;
            try
            {
                tx = session.BeginTransaction();
                for (int i = 0; objects != null && i < objects.Length; i++)
                {
                    if (objects[i] == null)
                    {
                        continue;
                    }
                    session.Save(objects[i]);
                }
                tx.Commit();
            }
            catch (Exception ex)
            {
                if (tx != null)
                {
                    tx.Rollback();
                }
                throw ex;
            }
            finally
            {
                session.Close();
            }
        }

        public void Update(params object[] objects)
        {
            ISession session = this.OpenSession();
            ITransaction tx = null;
            try
            {
                tx = session.BeginTransaction();
                for (int i = 0; objects != null && i < objects.Length; i++)
                {
                    if (objects[i] == null)
                    {
                        continue;
                    }
                    session.Update(objects[i]);
                }
                tx.Commit();
            }
            catch (Exception ex)
            {
                if (tx != null)
                {
                    tx.Rollback();
                }
                throw ex;
            }
            finally
            {
                session.Close();
            }
        }

        public void Delete(params object[] objects)
        {
            ISession session = this.OpenSession();
            ITransaction tx = null;
            try
            {
                tx = session.BeginTransaction();
                for (int i = 0; objects != null && i < objects.Length; i++)
                {
                    if (objects[i] == null)
                    {
                        continue;
                    }
                    session.Delete(objects[i]);
                }
                tx.Commit();
            }
            catch (Exception ex)
            {
                if (tx != null)
                {
                    tx.Rollback();
                }
                throw ex;
            }
            finally
            {
                session.Close();
            }
        }

        public DateTime GetDBMinTime()
        {
            return NHibernateHelper.GetDBMinTime();
        }

        public bool IsDBMinTime(DateTime time)
        {
            if (NHibernateHelper.GetDBMinTime() == time)
            {
                return true;
            }

            return Math.Abs(time.Subtract(NHibernateHelper.GetDBMinTime()).TotalDays) < 1;
        }
    }
}
